#include "io/sk_wcharfile.h"
#define MAX_INNERBUF_LEN 512
#define NEW_LINE_WCHAR 0xa
#define RETURN_WCHAR 0xd

struct SK_WCHAR_FILE{
	SK_FILE *m_pfile;
	SK_WCHAR *m_innerBuf;
	SK_INT32 m_innerBufLen;//count by char
	SK_INT32 m_curInnerBufPos;
};

SK_WCHAR_FILE * SK_WCHAR_FILE_open(const SK_WCHAR *path,SK_FILE_OPENMODE mode)
{
	SK_FILE *f = SK_FILE_open(path,mode);
	if (f)
	{
		SK_WCHAR_FILE *o = (SK_WCHAR_FILE *)SK_MEM_malloc(sizeof(SK_WCHAR_FILE));
		o->m_pfile = f;
		o->m_innerBuf = SK_MEM_malloc(MAX_INNERBUF_LEN * SIZEOF(SK_WCHAR));
		o->m_innerBufLen = MAX_INNERBUF_LEN;
		o->m_curInnerBufPos = o->m_innerBufLen + 1;//cause the first call of read to call fillBuf
		return o;
	}
	else
	{
		return SK_NULL;
	}
	
}

void SK_WCHAR_FILE_close(SK_WCHAR_FILE *o)
{
	if (o)
	{
		if (o->m_pfile)
		{
			SK_FILE_close(o->m_pfile);
		}
		SAFE_FREE(o->m_innerBuf);
		o->m_innerBufLen = 0;
		o->m_curInnerBufPos = 0;
	}
}

//
SK_INT32 _SK_WCHAR_FILE_fillBuf(SK_WCHAR_FILE *o)
{
	SK_INT32 toReadBytes = o->m_innerBufLen * SIZEOF(SK_WCHAR);
	SK_INT32 readChars = SK_FILE_read(o->m_pfile,o->m_innerBuf,toReadBytes) / SIZEOF(SK_WCHAR);
	o->m_curInnerBufPos = 0;
	o->m_innerBufLen = readChars;
	return readChars;
}


//return -1 :reach eof;
SK_INT32 _SK_WCHAR_FILE_getCharFromInnerBuf(SK_WCHAR_FILE *o)
{
	SK_INT32 c = -1;
	if (o->m_curInnerBufPos >= o->m_innerBufLen)
	{
		SK_INT32 readChars = _SK_WCHAR_FILE_fillBuf(o);
		if (readChars < 1)
		{
			//EOF
			c =  -1;
			return c;
		}
	}
	
	if (o->m_innerBuf[o->m_curInnerBufPos] == RETURN_WCHAR)
	{
			//skip '\r'
			o->m_curInnerBufPos ++;
			c =  _SK_WCHAR_FILE_getCharFromInnerBuf(o);
	}
	else
	{
			c = o->m_innerBuf[o->m_curInnerBufPos++];
	}
	
	
	return c;
}

//return read chars in the current line,-1 means reaching file end

SK_INT32 SK_WCHAR_FILE_readLine(SK_WCHAR_FILE *o,SK_WCHAR *buf,SK_INT32 len)
{
	if (o && o->m_pfile)
	{
		SK_INT32 addCharCount = 0;
		
		SK_INT32 result = 0;
		while (addCharCount < len - 1)
		{
			result = _SK_WCHAR_FILE_getCharFromInnerBuf(o);//get one char
			if (result == NEW_LINE_WCHAR)
			{
				break;
			}
			else if (result == -1)
			{
				//EOF
				break;
			}
			else
			{
				buf[addCharCount++] = (SK_WCHAR)result;	
			}
			
		}
		if (result == -1)
		{
			return -1;
		}
		else
		{
			buf[addCharCount] = 0;
			return addCharCount;
		}
		 
		
	}
	else
	{
		return -1;
	}
	
	
}

SK_INT32 SK_WCHAR_FILE_writeString(SK_WCHAR_FILE *o,const SK_WCHAR *buf)
{
	if (o && o->m_pfile)
	{
		SK_INT32 bufLen = SK_strlen(buf);
		SK_INT32 writeByteLen = SK_FILE_write(o->m_pfile,buf,bufLen * SIZEOF(SK_WCHAR));
		return writeByteLen / SIZEOF(SK_WCHAR);
	}
	else
	{
		return -1;
	}
	
}